package com.jiayou.config.vertx.handler.jwt


import com.jiayou.config.vertx.VertxApplication
import io.vertx.core.AsyncResult
import io.vertx.core.Future
import io.vertx.core.Handler
import io.vertx.core.json.JsonObject
import io.vertx.ext.auth.User
import io.vertx.ext.auth.authentication.TokenCredentials
import io.vertx.ext.auth.jwt.JWTAuth
import io.vertx.ext.web.RoutingContext
import io.vertx.ext.web.handler.HttpException
import io.vertx.ext.web.handler.impl.JWTAuthHandlerImpl
import org.springframework.util.AntPathMatcher

/**
@author lishuang
@data   2021-06-25  10:31:04
@info   jwt检测处理器
 */
open class JwtHandler(authProvider: JWTAuth, realm: String? = null) : JWTAuthHandlerImpl(authProvider, realm) {
    private val antPathMatcher = AntPathMatcher()
    override fun authenticate(context: RoutingContext, handler: Handler<AsyncResult<User>>) {
        val currentPath = context.request().path()
        if ("/*" in VertxApplication.filtrationURL) {
            context.next()
            return
        }
        for (filtrationURLItem in VertxApplication.filtrationURL) {
            if (antPathMatcher.match(filtrationURLItem, currentPath)) {
                context.next()
                return
            }
        }
        parseAuthorization(context) { parseAuthorization: AsyncResult<String> ->
            if (parseAuthorization.failed()) {
                handler.handle(errorHandleInfo())
                return@parseAuthorization
            }
            val token = parseAuthorization.result()
            var segments = 0
            for (element in token) {
                if (element == '.') {
                    if (++segments == 3) {
                        handler.handle(errorHandleInfo())
                        return@parseAuthorization
                    }
                    continue
                }
                if (Character.isLetterOrDigit(element) || element == '-' || element == '_') {
                    continue
                }
                // invalid character
                handler.handle(errorHandleInfo())
                return@parseAuthorization
            }
            authProvider.authenticate(TokenCredentials(token), { authn: AsyncResult<User> ->
                if (authn.failed()) {
                    handler.handle(errorHandleInfo())
                } else {
                    handler.handle(authn)
                }
            })
        }
    }

    open fun errorHandleInfo(): Future<User> = Future.failedFuture(HttpException(401, Exception(JsonObject().put("code", 401).put("message", "禁止访问！").put("data", null).encode())))

}